﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using MvcApplication2.Models;

namespace MvcApplication2.Controllers
{
    [Authorize]
    public class DeveloperExerciseController : ControllerEx
    {
        /*
         * un'altra cosa che devo guardare e la gestione dell'esercizi.
         * 
         * posso cancellarlo mentre altri utenti hanno già contratto esercizio..
         * si magari voto negativo a user. magari dev può ricevere valutazione negativa.
         * 
         * una volta che utente rifiuta proposta ( previo conferma ). magari qui basta js.
         * la proposta viene cancellata dalla tua lista visibile. e vieni rimosso da utenti allowed.
         * 
         * l'altro utente appare .. cancellato. con pulsante rimuovi.
         * 
         * 
         */
        private MvcApplication2Context db = new MvcApplication2Context();

        public DeveloperExerciseController()
        {
            /// metterlo in viewmodel..
            ViewBag.Devices = db.Devices.ToList();
        }
        //
        // GET: /DeveloperExercise/

        public ActionResult Index()
        {
            var u = ModelHelper.GetUser(db);

            return View(u.Exercises.ToList());
        }


        /// <summary>
        /// Mostra la lista dei tester compatibili con l'esercizio corrente
        /// . fare paging .
        /// </summary>
        public ActionResult FindTesters(int id = 0)
        {
            ViewBag.exerciseId = id;

            // fare inclusione utente
            var exercise = db.Exercises.Find(id);
            if (exercise == null) return View();

            var dev = exercise.Owner;
            //var testers =
            //   db.UsersProfiles.Where(
            //       k => k.Languages.Intersect(user.Languages).Any() && k.Devices.Contains(exercise.Device)).ToList();

            //IEnumerable<UserProfile> testers = new List<UserProfile>();
            //foreach (var language in dev.Languages)
            //{
            //    var language1 = language;
            //    var temp =
            //        db.UsersProfiles.Where(u => u.AcceptTestingRequest && u.Devices.Any(p => p.DeviceId == exercise.Device.DeviceId) && u.Languages.Any(l => l.LanguageId == language1.LanguageId));

            //    testers = testers.Union(temp);
            //}
            var testers = (from u in db.UsersProfiles.Include(us => us.Languages).Include(us=>us.Devices)
                           from t in db.UsersProfiles.Where(de=>de.UserProfileId == dev.UserProfileId)
                           from e in db.Exercises.Where(de => de.ExerciseId== exercise.ExerciseId)
                           where u.AcceptTestingRequest
                           from d in u.Devices
                           from lan in u.Languages
                           from lanOwner in t.Languages
                           where d.DeviceId == e.DeviceId
                           where lan.LanguageId == lanOwner.LanguageId
                           select u).ToList();

            var vm = new FindTesterViewModel();

            // In base al device setto prorietà.
            vm.ExerciseTitle = exercise.Title;
            vm.CanScreenCapture = true;
            vm.CanWebcamRecording = true;

            foreach (var language in dev.Languages)
            {
                vm.LanguagesFiltered += language.Description;
            }

            foreach (var userProfile in testers)
            {
                var testerVm = ModelHelper.CopyTo<UserProfile, UserProfileFindTesterViewModel>(userProfile);

                var alredySended =
                    (db.UserMessages.Include(m => m.UsersAllowed).Where(
                        m =>
                        m.ExerciseId == exercise.ExerciseId &&
                        m.Type == UserMessageType.TesterExercise &&
                        m.UsersAllowed.Any(o => o.UserProfileId == userProfile.UserProfileId))).Any();

                var message = "No proposte in corso";

                if (alredySended)
                    message = "Proposta già spedita !";

                testerVm.ProposalSendedMessage = message;

                vm.Testers.Add(testerVm);
            }

            if (exercise.Device != null) vm.TargetDevice = exercise.Device.Description;

            return View(vm);
        }

        public ActionResult AskDifferentPrice(int id = 0)
        {
            var user = ModelHelper.GetUser(db);

            var viewModel = UserMessageHelper.GetProposal(id, db, false);

            if (viewModel == null) return RedirectToAction("MyExercises");

            return View("SendProposal", viewModel);
        }

        [HttpPost]
        public ActionResult AskDifferentPrice(UserMessageViewModel proposal, FormCollection formCollection)
        {
            var success = UserMessageHelper.CreateChildProposal(db, proposal.UserMessageId, proposal.Reward, proposal.Message,
                                                                        "tester");
            if (success)
            {
                return RedirectToAction("MyExercises");
            }

            // todo: inserire messaggi di errore
            return RedirectToAction("SendProposal", proposal.UserMessageId);
        }

        /// <summary>
        /// Dev side.
        /// Mando proposta a utente,
        /// Creo message vuoto solamente con testerid e exerciseid in modo da identificarlo successivamente
        /// </summary>
        [Authorize]
        public ActionResult SendProposal(int exerciseId = 0, int testerId = 0)
        {
            var exmessage = UserMessageHelper.GetTesterExercise(db, exerciseId, testerId);

            var vm = ModelHelper.CopyTo<UserMessage, UserMessageViewModel>(exmessage);

            return View(vm);
        }

        /// <summary>
        /// Qui verrà creato il messaggio di proposta
        /// </summary>
        [HttpPost]
        [Authorize]
        public ActionResult SendProposal(UserMessageViewModel mess, FormCollection formCollection)
        {
            var success = UserMessageHelper.CreateTesterExercise(db, mess.ExerciseId, mess.TesterId, mess.Reward, mess.Message, "dev");

            if (success)
            {
                AddSuccessMessage("Proposta Inviata !");
            }
            else
            {
                AddSuccessMessage("Errore proposta !");

            }
            return RedirectToAction("FindTesters", new RouteValueDictionary() { { "id", mess.ExerciseId } });
        }

        /*
         * Una volta accettato esercizio, posso creare cancellare tutti o forse e meglio di no.
         * cosi riesco a tenere salvati i messaggi.
         * setto inattivo e setto completato il seguente.
         * cosi posso tenere traccia anche degli altri cambi di stato e messaggi sempre inerenti all'esercizio
         */
        public ActionResult AcceptTestExercise(int id = 0)
        {
            var test = db.UserMessages.Find(id);

            test.ExerciseStatus = ExerciseStatusType.WaitingTest;

            db.SaveChanges();


            return RedirectToAction("MyExercises");
        }

        // Lista dei messaggi riguardanti proposte di lavoro .
        [Authorize]
        public ActionResult MyExercises(string filter)
        {
            var user = ModelHelper.GetUser(db);

            var vms1 = UserMessageHelper.GetExercises(db, user.UserProfileId, false);

            //var workMsg =
            //    db.UserMessages.Include(t => t.Exercise).Include(t => t.ParentMessage).Where(m => m.Type == ThreadMessageType.TesterExercise && m.ExerciseStatus == ExerciseStatusType.ProposalActive).Where(
            //        m1=> m1.ParentMessage.UsersAllowed.Any(m2 => m2.UserId == user.UserId)).ToList();

            ////var workMsg =
            ////    db.UserMessages.Include(l=>l.).Where(m => m.Type == (byte)ThreadMessageType.TesterExercise).Where(
            ////        m1 => m1.Owner.UserId == user.UserId || m1.UsersAllowed.Any(m2 => m2.UserId == user.UserId)).ToList();

            //var vms = ModelHelper.GetListViewModel<UserMessage, ExerciseTestViewModel>(workMsg);

            //foreach (var vm in vms)
            //{
            //    vm.IsTesterSide = false;
            //}

            return View(vms1);
        }

        /*
         * In alternativa posso mettere rating tester e rating owner con relativi commenti, ma non è molto espandibile.
         * Altrimenti genero i 2 user al momento della creazione del user dell'esercizio principale.
         * poi con viewmodel passo solo quello che mi serve.
         * 
         * creo 2 threadrating per ogni proposta ?
         * o lo uso chiave combinata user - user ?
         * 
         * type
         * user-rating-dev
         * rating-tester
         * 
         * devo fare anche un layer per accesso ai dati , in modo che user posso editare solamente i propri record.
         */

        //public ActionResult VoteUser(int id = 0)
        //{
        //    //if(tmessage == 0)
        //    //{
        //    var ex = db.UserMessages.Include(o => o.UserMessages).FirstOrDefault(o => o.UserMessageId == id);

        //    if (ex == null) return RedirectToAction("MyExercises");

        //    var testerRating = ex.UserMessages.FirstOrDefault(l => l.Type == UserMessageType.RatingTester);

        //    if (testerRating == null) return RedirectToAction("MyExercises");

        //    // magari creo vm
        //    return View(testerRating);
        //}

        //[HttpPost]
        //public ActionResult VoteUser(UserMessage user, FormCollection formCollection)
        //{
        //    var ratingThread = db.UserMessages.Find(user.UserMessageId);

        //    var messagge = formCollection["Message"];
        //    var rating = formCollection["Rating"];

        //    ratingThread.Message = messagge;
        //    ratingThread.Rating = byte.Parse(rating);

        //    db.SaveChanges();

        //    return RedirectToAction("MyExercises");

        //    //if (ratingThread == null)
        //    //{
        //    //    var threadMessage = UserMessage.CreateRating(ModelHelper.GetUser(db), user.Rating, "dev");

        //    //    db.UserMessages.Add(threadMessage);
        //    //    db.SaveChanges();

        //    //    if (ModelState.IsValid)
        //    //    {
        //    //    }
        //    //    //return View();
        //    //    ViewBag.exerciseId = exid;

        //    //    return RedirectToAction("FindTesters", new RouteValueDictionary() { { "id", exid } });
        //    //}

        //    //else
        //    //{

        //    //}

        //    //return View(user);
        //}

      
        public ActionResult Create()
        {
            ViewBag.Title = "Create";
            return View("Edit");
        }

        //
        // POST: /DeveloperExercise/Create

        [HttpPost]
        public ActionResult Create(Exercise exercise, FormCollection formCollection)
        {
            ViewBag.Title = "Create";
            var save = formCollection["save"];
            var publish = formCollection["publish"];

            var u = ModelHelper.GetUser(db);

            exercise.Owner = u;
            exercise.OwnerId = u.UserProfileId;
            exercise.Status = "draft";

            if (exercise.ExerciseId == 0)
            {
                db.Exercises.Add(exercise);
                db.SaveChanges();
            }
            else
            {
                exercise = db.Exercises.Find(exercise.ExerciseId);
                TryUpdateModel(exercise, formCollection);
            }

            if (publish != null)
            {
                exercise.Status = "published";
                //db.SaveChanges();
                //return RedirectToAction("Index");
            }

            db.SaveChanges();
            return RedirectToAction("Index");

            //return RedirectToAction("Edit", new RouteValueDictionary(){{"id",exercise.ExerciseId}});
        }

        //
        // GET: /DeveloperExercise/Edit/5

        public ActionResult Edit(int id = 0)
        {
            ViewBag.Title = "Edit";

            Exercise exercise = db.Exercises.Find(id);
            if (exercise == null)
            {
                return HttpNotFound();
            }
            return View(exercise);
        }

        //
        // POST: /DeveloperExercise/Edit/5

        [HttpPost]
        public ActionResult Edit(Exercise exercise, FormCollection formCollection)
        {
            ViewBag.Title = "Edit";
            var save = formCollection["save"];
            var publish = formCollection["publish"];

            if (ModelState.IsValid)
            {
                if (publish != null)
                    exercise.Status = "published";

                db.Entry(exercise).State = EntityState.Modified;
                db.SaveChanges();
                return RedirectToAction("Index");
            }


            return View(exercise);
        }

        //
        // GET: /DeveloperExercise/Delete/5

        public ActionResult Delete(int id = 0)
        {
            Exercise exercise = db.Exercises.Find(id);
            if (exercise == null)
            {
                return HttpNotFound();
            }
            return View(exercise);
        }

        //
        // POST: /DeveloperExercise/Delete/5

        [HttpPost, ActionName("Delete")]
        public ActionResult DeleteConfirmed(int id)
        {
            //Exercise exercise = db.Exercises.Find(id);

            //var p2 = exercise.UserMessages;

            var exercise1 = db.Exercises.Include(t => t.ThreadMessages).First(p => p.ExerciseId == id);

            //var p1 = exercise.UserMessages;
            db.Exercises.Remove(exercise1);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        protected override void Dispose(bool disposing)
        {
            db.Dispose();
            base.Dispose(disposing);
        }
    }
}